'''
Created on Aug 28, 2013

@author: loski07@gmail.com
'''
from model.exceptions import FolderException
import os
import platform.system
import shutil
import subprocess

class DeviceManager(object):
    """
    Class with operations to manage the external device.
    p = subprocess.Popen('/usr/bin/sudo /usr/bin/touch /tmp/foo2.txt', stdin=PIPE, stdout=PIPE, shell=True)
    """

    @staticmethod
    def get_device_manager(self):
        target = platform.system().lower()
        if 'windows' in target:
            return DeviceManagerWin()
        elif 'linux' in target:
            return DeviceManagerNix()
        else:
            # error
            pass

    def calculate_available_size(self, path):
        pass
                
    def calculate_folder_size(self, path):
        pass
    
    def check_folder(self, folder):
        """
        Checks the existence of the target folder.
        If it exists, it also returns the available disk space in KB.
        
        @param folder: path to the target folder.
        @return: Dictionary with keys 'name' and 'size' that stores the full
            path to the target and the available size in KB.
        @raise FolderException: Exception accessing the target folder.
        """
        dsm = DeviceManager()
        if os.path.exists(folder):
            return {'name': os.path.realpath(folder),
                    'size': dsm.calculate_available_size(folder)}
        raise FolderException()
    

    def copy_song(self, src_path, song_name, tgt_path):
        tgt_song_path = os.path.join(tgt_path, song_name)
        src_song_path = os.path.join(src_path, song_name)
        shutil.copy(src_song_path, tgt_song_path)
        

            
    def removeSong(self, path):
        pass
    
    def removeFolder(self, path):
        # TODO: error handling
        shutil.rmtree(path)
        
class DeviceManagerNix(DeviceManager):
    
    def calculate_available_size(self, path):
        """
        Calculates the available space of the device in which the path is mounted.
        
        @param path: path to check
        @return: free disk space in KB
        """
        df = subprocess.Popen(['df', '-k', path], stdout=subprocess.PIPE)
        output = df.communicate()[0]
        i = 0
        for x in output.split('\n')[0].split():
            if x.lower() in ['available', 'free']:
                return float(output.split('\n')[1].split()[i])
            else:
                i += 1
    
    def calculate_folder_size_linux(self, path):
        """
        Calculates the size of the folder in KB in a Linux/Unix target machine.
        @param param: path to check
        @return: size in KB
        """
        df = subprocess.Popen(['du', '-ks', path], stdout=subprocess.PIPE)
        return df.communicate()[0] / 1024
        
#         total_size = 0.0
#         for x in os.listdir(path):
#             if not x.startswith('.'):
#                     subitem = os.path.join(path, x)
#                     if os.path.isdir(subitem):
#                         total_size += self.calculate_folder_size_linux(subitem)
#                     else:
#                         if subitem[-4:].lower() in ['.mp3', '.wma']:
#                             total_size += os.path.getsize(subitem)
#         return total_size / 1024

    def formatDevice(self, device_mount_point, label = None, password):
        """
        Formats the target device.
        @param device_mount_point: mounting point of the device to format.
        @param label: label to set to the device
        """
        format_command = '/usr/bin/sudo /sbin/mkfs.vfat {0}'.format(device_mount_point)
        label_command = '/sbin/e2label {0} {1}'.format(device_mount_point, label)
        try:
            #Uses pexpect to manage password.
            import pexpect
             
            child = pexpect.spawn(format_command) 
            i = child.expect(['ssword', pexpect.EOF, pexpect.TIMEOUT])
            if i ==0:
                child.sendline(password) 
                child.expect(pexpect.EOF)
            if label:
                child.sendline(label_command)
                i = child.expect(['ssword', pexpect.EOF, pexpect.TIMEOUT])
                if i == 0:
                    child.sendline(password) 
                    child.expect(pexpect.EOF)
            child.close()
        except:
            #No pyexpect installed.
            #This approach will ask for password within the console.
            subprocess.Popen(format_command, stdin = subprocess.PIPE,
                              stdout = subprocess.PIPE, shell = True)
            if label:
                subprocess.Popen(label_command, stdin = subprocess.PIPE,
                              stdout = subprocess.PIPE, shell = True)
             
    
class DeviceManagerWin(DeviceManager):
    
    def calculate_available_size(self, path):
        """
        Calculates the available space of the device in a Window$ target machine.
        
        @param path: path to check
        @return: free disk space in KB
        """
        import win32file
        
        secsPerClus, bytesPerSec, nFreeClus, totClus = win32file.GetDiskFreeSpace(path)
        return secsPerClus * bytesPerSec * nFreeClus /1024

    def calculate_folder_size(self, path):
        """
        Calculates the size of the folder in KB in a Window$ target machine.
        @param param: path to check
        @return: size in KB
        """
        import win32com.client as com
        
        fso = com.Dispatch("Scripting.FileSystemObject")
        folder = fso.GetFolder(path)
        
        return folder.Size / 1024